package com.hamilton.erik.pt.core.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.hamilton.erik.pt.core.dao.NoteDAO;
import com.hamilton.erik.pt.core.db.H2JdbcAccess;
import com.hamilton.erik.pt.core.model.Note;
import com.hamilton.erik.pt.core.util.SqlUtil;

public class H2NoteDAO implements NoteDAO {
	
	private final String INSERT_STATEMENT_FORMAT = 
							"INSERT INTO %s (REFERENCE_ID, TITLE, NOTE, NOTE_DATE) " +
							"VALUES (?, ?, ?, ?)";
	
	private final String UPDATE_STATEMENT_FORMAT =
			"UPDATE %s SET TITLE=?, NOTE=?, NOTE_DATE=? WHERE ID=?";
	
	private final String DELETE_STATEMENT_FORMAT =
								"DELETE FROM %s WHERE ID=?";
	
	private final String GET_ALL_NOTES_STATEMENT_FORMAT =
							"SELECT * FROM %s WHERE REFERENCE_ID = ? ORDER BY NOTE_DATE ASC";
	
	private final String DELETE_ALL_NOTES_STATEMENT_FORMAT =
								"DELETE FROM %s WHERE REFERENCE_ID=?";

	@Override
	public int insertNote(Note note, String table) throws SQLException {

		int insertedRow = -1;
		Connection conn = null;
		
		try {
			conn = H2JdbcAccess.getInstance().getConnection();
			conn.setAutoCommit(false);
						
			PreparedStatement stmt = conn.prepareStatement(
										buildStatement(INSERT_STATEMENT_FORMAT, table));
		
			stmt.setLong(1, note.getReferenceId());
			stmt.setString(2, note.getTitle());
			stmt.setString(3, note.getNote());
			SqlUtil.setStringOrNull(4, stmt, note.getDate());
			
			insertedRow = stmt.executeUpdate();
			
			conn.commit();

			return insertedRow;
		} catch (SQLException e) {
			throw e;
		} finally {
			if(conn != null) try { conn.close(); } catch (Exception ignore) {}
		}
	}

	@Override
	public boolean deleteNote(Long noteId, String table) throws SQLException {

		int returnValue = -1;
		Connection conn = null;
		
		try {
			conn = H2JdbcAccess.getInstance().getConnection();
			conn.setAutoCommit(false);
						
			PreparedStatement stmt = conn.prepareStatement(
										buildStatement(DELETE_STATEMENT_FORMAT, table));

			stmt.setLong(1, noteId);
			
			returnValue = stmt.executeUpdate();
			
			conn.commit();

			if(returnValue > 0) {
				return true;
			}
		} catch (SQLException e) {
			throw e;
		} finally {
			if(conn != null) try { conn.close(); } catch (Exception ignore) {}
		}
		
		return false;
	}

	@Override
	public Note findNote(Note note, String table) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int updateNote(Note note, String table) throws SQLException {

		int updatedRow = -1;
		Connection conn = null;
		
		try {
			conn = H2JdbcAccess.getInstance().getConnection();
			conn.setAutoCommit(false);
						
			PreparedStatement stmt = conn.prepareStatement(
										buildStatement(UPDATE_STATEMENT_FORMAT, table));

			stmt.setString(1, note.getTitle());
			stmt.setString(2, note.getNote());
			SqlUtil.setStringOrNull(3, stmt, note.getDate());
			stmt.setLong(4, note.getId());
			
			updatedRow = stmt.executeUpdate();
			
			conn.commit();

			return updatedRow;
		} catch (SQLException e) {
			throw e;
		} finally {
			if(conn != null) try { conn.close(); } catch (Exception ignore) {}
		}
	}

	@Override
	public List<Note> getAllNotes(Long referenceId, String table) throws SQLException {

		List<Note> notes = new ArrayList<Note>();
		Connection conn = null;
		
		try {
			conn = H2JdbcAccess.getInstance().getConnection();
						
			PreparedStatement stmt = conn.prepareStatement(
										buildStatement(GET_ALL_NOTES_STATEMENT_FORMAT, table));
		
			stmt.setLong(1, referenceId);
			
			ResultSet rs = stmt.executeQuery();
			
			while(rs.next()) {
				Note newNote = new Note();
				
				newNote.setId(rs.getLong(1));
				newNote.setReferenceId(rs.getLong(2));
				newNote.setTitle(rs.getString(3));
				newNote.setNote(rs.getString(4));
				newNote.setDate(rs.getString(5));
				
				notes.add(newNote);
			}
			
			return notes;
			
		} catch (SQLException e) {
			throw e;
		} finally {
			if(conn != null) try { conn.close(); } catch (Exception ignore) {}
		}
	}

	private String buildStatement(String statementFormat, String table) {
		return String.format(statementFormat, table);
	}

	@Override
	public boolean deleteAllNotes(Long referenceId, String table) throws SQLException {

		int returnValue = -1;
		Connection conn = null;
		
		try {
			conn = H2JdbcAccess.getInstance().getConnection();
			conn.setAutoCommit(false);
						
			PreparedStatement stmt = conn.prepareStatement(
										buildStatement(DELETE_ALL_NOTES_STATEMENT_FORMAT, table));

			stmt.setLong(1, referenceId);
			
			returnValue = stmt.executeUpdate();
			
			conn.commit();

			if(returnValue > 0) {
				return true;
			}
		} catch (SQLException e) {
			throw e;
		} finally {
			if(conn != null) try { conn.close(); } catch (Exception ignore) {}
		}
		
		return false;
	}
}
